﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Xml.Serialization;
using System.IO;
using VCSKicksCollection;

namespace DSA___semestralkaA___2
{
    public partial class Form1 : Form
    {


        #region Inicializace programu
        public Bitmap bmp;
        Graphics g;
        private int akceTyp = 0;
        private string logText;
        public string LogText
        {
            get { return logText; }
            set { textBox1.Text = (logText = value + "\r\n" + logText); }
        }
        private string vysledky;
        public string Vysledky
        {
            get { return vysledky; }
            set
            {
                textBox3.Text = (vysledky = value + "\r\n----------------------------------------------------------------" +
                    "\r\n----------------------------------------------------------------\r\n" + vysledky);
            }
        }
        public bool PROBIHAIMPORT = false;
        public int cenaCesty = 0;
        public Mesto vychoziUzelCesty = null;
        static BackgroundWorker bw = new BackgroundWorker();
        Dijkstra da = new Dijkstra();
        Graf<Mesto, Hrana<Mesto, int>> graf = new Graf<Mesto, Hrana<Mesto, int>>();

        List<Point> oznaceneBody = new List<Point>();
        List<Mesto> zasobnikNaMesta = new List<Mesto>();
        #endregion

        #region Dijkstrův algoritmus + metoda pro vykreslování od PB
        //ukládám označené body, mezi kterými budu kreslit přímku a vkládat do grafu

        List<Mesto> dijkstrovaCesta = new List<Mesto>();

        //public void DijkTest(Mesto startProhledavani)
        //{
        //    //inicializace vrcholů
        //    Dictionary<Mesto, Mesto> predchoziVrchol = new Dictionary<Mesto, Mesto>();
        //    Dictionary<Mesto, int> vzdalenost = new Dictionary<Mesto, int>();
        //    List<Mesto> nenavstivene = new List<Mesto>();


        //    //seznam všech uzlů
        //    foreach (Mesto item in graf)
        //    {
        //        predchoziVrchol.Add(item, null);
        //        nenavstivene.Add(item);
        //        vzdalenost.Add(item, 1000);
        //    }

        //    vzdalenost[startProhledavani] = 0;

        //    int vz = 1000;
        //    Mesto nejmensi = null;
        //    foreach (Mesto m in nenavstivene)
        //    {
        //        int tmp = vzdalenost[m];
        //        if (tmp < vz)
        //        {
        //            vz = tmp;
        //            nejmensi = m;
        //        }
        //    }


        //    while (nenavstivene.Count > 0 && nejmensi.NazevMesta != "B")
        //    {

        //        //výběr uzlu s nejmenší vzdáleností
        //        vz = 1000;
        //        nejmensi = null;
        //        foreach (Mesto m in nenavstivene)
        //        {
        //            int tmp = vzdalenost[m];
        //            if (tmp < vz)
        //            {
        //                vz = tmp;
        //                nejmensi = m;
        //            }
        //        }
        //        nenavstivene.Remove(nejmensi);


        //        //ošetření proti nedosažitelným cestám
        //        if (nejmensi == null)
        //        {
        //            nenavstivene.Clear();
        //        }
        //        else
        //        {
        //            foreach (Hrana<Mesto, int> hrana in graf.vratSeznamHranVUzlu(nejmensi))
        //            {
        //                //výběr opačného uzlu
        //                Mesto prvni, druhy;
        //                if (hrana.vratUzelA().getX() == nejmensi.getX())
        //                {
        //                    prvni = (Mesto)hrana.vratUzelB();
        //                    druhy = (Mesto)hrana.vratUzelA();
        //                }
        //                else
        //                {
        //                    prvni = (Mesto)hrana.vratUzelA();
        //                    druhy = (Mesto)hrana.vratUzelB();
        //                }


        //                int novaVzdalenost = vzdalenost[nejmensi] + vratOhodnoceniHrany(prvni, druhy);
        //                if (novaVzdalenost < vzdalenost[prvni])
        //                {
        //                    vzdalenost[prvni] = novaVzdalenost;
        //                    predchoziVrchol[prvni] = nejmensi;
        //                }


        //            }

        //        }
        //    }

        //    foreach (var pair in vzdalenost)
        //    {
        //        Console.WriteLine("{0}, {1}", pair.Key, pair.Value);
        //    }

        //    string s = "";
        //    foreach (var item in predchoziVrchol)
        //    {
        //        s += vzdalenost[item.Key] + " -> " + item.Key + " -> " + item.Value + "--------\r\n";
        //    }

        //    Vysledky = s;
        //}


        //public List<Mesto> DijkstraTest(Mesto startProhledavani, Mesto startProhledavani2 , int pomer1 , int pomer2 )
        //{

        //    Dictionary<Mesto, Mesto> predchoziVrchol = new Dictionary<Mesto, Mesto>(); //kvůli backtrakingu
        //    Dictionary<Mesto, int> vzdalenost = new Dictionary<Mesto, int>(); //pro výpočet nejkratší vzdálenosti
        //    PriorityQueue<Mesto> fronta = new PriorityQueue<Mesto>(); //hlavní struktura
        //    PriorityQueue<Mesto> nejblizsiPZS = new PriorityQueue<Mesto>();

        //    //inicializace
        //    foreach (Mesto item in graf)
        //    {
        //        predchoziVrchol.Add(item, null);
        //        if (!item.Equals(startProhledavani) || !item.Equals(startProhledavani2))
        //        { vzdalenost.Add(item, 100000); }
        //    }

        //    //vložím první vrchol do fronty a nastavím vzdálenost
        //    if (startProhledavani2 == null)
        //    {
        //        fronta.Enqueue(startProhledavani);
        //        vzdalenost[startProhledavani] = 0;
        //    }
        //    else
        //    {
        //        startProhledavani.Cena = pomer1;
        //        fronta.Enqueue(startProhledavani);
        //        vzdalenost[startProhledavani] = pomer1;

        //        startProhledavani2.Cena = pomer2;
        //        fronta.Enqueue(startProhledavani2);
        //        vzdalenost[startProhledavani2] = pomer2;
        //    }



        //    Mesto mesto;
        //    Mesto konecna = null;
        //    //dělám, dokud ve frontě ještě něco je
        //    while (fronta.Count > 0)
        //    {

        //        //odeberu prioritní prvek z fronty
        //        mesto = fronta.Dequeue();

        //        //if (mesto.PZS == true) { nejblizsiPZS.Enqueue(mesto); break; }



        //        //prioritní vytahování incidentních hran
        //        //tady je potřeba udělat natahování do listu!!!!
        //        foreach (Hrana<Mesto, int> hrana in graf.vratSeznamHranVUzlu(mesto))
        //        {
        //            //if (konecna != null) break;

        //            //výběr opačného uzlu
        //            Mesto prvni, druhy;
        //            if (hrana.vratUzelA().getX() == mesto.getX())
        //            {
        //                prvni = (Mesto)hrana.vratUzelB();
        //                druhy = (Mesto)hrana.vratUzelA();
        //            }
        //            else
        //            {
        //                prvni = (Mesto)hrana.vratUzelA();
        //                druhy = (Mesto)hrana.vratUzelB();
        //            }


        //            int novaVzdalenost = vzdalenost[mesto] + vratOhodnoceniHrany(prvni, druhy);
        //            if (novaVzdalenost < vzdalenost[prvni])
        //            {
        //                vzdalenost[prvni] = novaVzdalenost;
        //                prvni.Cena = novaVzdalenost;
        //                predchoziVrchol[prvni] = mesto;
        //                fronta.Enqueue(prvni);



        //                //if (prvni.PZS == true) { nejblizsiPZS.Enqueue(prvni); }
        //                //pokud je to pozemní záchranná pozemní stanice, tak končím
        //            }


        //        }



        //        if (konecna == null)
        //        {
        //            if (mesto.PZS == true) { konecna = mesto; break; }
        //        }
        //        else
        //        {
        //            if (mesto.PZS == true && konecna.Cena > mesto.Cena) { konecna = mesto; break; }
        //        }


        //    }

        //    //konecna = nejblizsiPZS.Dequeue();

        //    string s = "";



        //    //tady bude traverzování
        //    //-- vyberu uzel s nejmenší hodnotou "konecna", který má PSZ
        //    //-- pak se vracím zpět


        //    if (konecna == null)
        //    { s += "Cesta nebyla nalezena pro bod: " + startProhledavani.NazevMesta; }
        //    else
        //    {
        //        cenaCesty = konecna.Cena;

        //        //backtracking -> uložení do listu
        //        string zz = konecna.ToString();
        //        Mesto tmp = konecna;
        //        List<Mesto> lp = new List<Mesto>();
        //        lp.Add(konecna);
        //        s += "Vyhledávám nejkratší cestu\r\n\r\n";
        //        if (cenaCesty == 0)
        //        {
        //            s += "V tomto městě je záchranka";
        //        }
        //        else
        //        {

        //            s += "Cena cesty: " + cenaCesty + "\r\n\r\n";
                
        //        }
        //        s += " -> " + konecna.getName();
        //        vychoziUzelCesty = konecna;


        //        while (startProhledavani != tmp)
        //        {
        //            if (startProhledavani2 == tmp)
        //            {
        //                break;
        //            }
        //            else
        //            {

        //                tmp = predchoziVrchol[tmp];
        //                lp.Add(tmp);
        //                s += " -> " + tmp.getName();
        //                vychoziUzelCesty = tmp;
        //            }

        //        }



        //        //výpis výsledku
        //        s += "\r\n\r\n";
        //        foreach (var item in predchoziVrchol)
        //        {
        //            s += vzdalenost[item.Key] + " -> " + item.Key + " -> " + item.Value + "\r\n";
        //        }
        //        Vysledky = s;

        //        //vrátím cestu
        //        dijkstrovaCesta = lp;
        //        return dijkstrovaCesta;
        //    }

        //    //výpis výsledku pro případ, že nenajdu cestu
        //    s += "\r\n------------\r\n";
        //    foreach (var item in predchoziVrchol)
        //    {
        //        s += vzdalenost[item.Key] + " -> " + item.Key + " -> " + item.Value + "\r\n";
        //        dijkstrovaCesta.Remove(item.Key);
        //    }
        //    Vysledky = s;
        //    return dijkstrovaCesta;

        //}

        /// <summary>
        /// Metoda pro vykreslení do GUI
        /// </summary>
        /// <param name="cesta">Přijímá seznam měst -> seznam musí být utříděný</param>
        public void vykresliDijstra(List<Mesto> cesta)
        {
            Graphics g = Graphics.FromImage(pictureBox1.Image);
            if (cesta.Count > 0)
            {

                int index1 = 0;
                int index2 = 1;

                for (int i = 1; i < cesta.Count; i++)
                {
                    Point p1 = new Point(cesta.ElementAt(index1).getX(), cesta.ElementAt(index1).getY());
                    Point p2 = new Point(cesta.ElementAt(index2).getX(), cesta.ElementAt(index2).getY());

                    g.DrawLine(new Pen(Color.HotPink, 10), p1, p2);
                    index1++;
                    index2++;

                }
                Vysledky = "Vykresluji nejkratší cestu";
            }
            g.Save();

            pictureBox1.Image = bmp;
        }

        #endregion

        public void najdiPokrytaMesta(Mesto mesto)
        {
            //zadám bod letiště - z toho se vypočítá čtverec
            //vytvořím levýHorní a pravýDolní
            Mesto levyHorni = new Mesto((mesto.X - (mesto.LZS / 2)), (mesto.Y - (mesto.LZS / 2)));
            Mesto pravyDolni = new Mesto((mesto.X + (mesto.LZS / 2)), (mesto.Y + (mesto.LZS / 2)));
            string vypis = "V okruhu " + mesto.LZS + "px od LZS " + mesto.NazevMesta + " (x:" + mesto.X + " | " + mesto.Y + ") jsou následující města: \r\n";
            Dictionary<Mesto, int> interval = graf.intervaloveVyhledavani(levyHorni, pravyDolni, mesto, (mesto.LZS));
            
            int pocet = 0;
            foreach (KeyValuePair<Mesto, int> m in interval)
            {
                vypis += (m.Key.ToString() + " -> LV: " + m.Value.ToString() + "\r\n");
                pocet++;
            }

            
            Vysledky = "Celkový počet: " +pocet +"\r\n"+ vypis;
        }


        public Form1()
        {
            InitializeComponent();
            bmp = new Bitmap(1640, 777);
            pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;  
            pictureBox1.Image = bmp;
            g = Graphics.FromImage(bmp);
            LogText = "Aplikace byla spuštěna, vyberte akci";







           /* Mesto a = new Mesto(450, 20, "A", false, 0);
            Mesto b = new Mesto(350, 150, "B", true, 400);
            Mesto c = new Mesto(33, 44, "C", false, 0);
            Mesto d = new Mesto(133, 324, "D", false, 0);
            Mesto e = new Mesto(833, 144, "E", false, 0);

            ////přidávání uzlů do grafu
            graf.pridejUzelDoGrafu(a);
            graf.pridejUzelDoGrafu(b);
            graf.pridejUzelDoGrafu(c);
            graf.pridejUzelDoGrafu(d);
            graf.pridejUzelDoGrafu(e);

            ////přidávání hran do grafu
            Hrana<Mesto, int> h1 = new Hrana<Mesto, int>(a, b, 3);
            Hrana<Mesto, int> h2 = new Hrana<Mesto, int>(a, c, 10);
            Hrana<Mesto, int> h3 = new Hrana<Mesto, int>(c, d, 40);
            Hrana<Mesto, int> h4 = new Hrana<Mesto, int>(d, e, 8);
            Hrana<Mesto, int> h5 = new Hrana<Mesto, int>(a, e, 10);
            Hrana<Mesto, int> h6 = new Hrana<Mesto, int>(b, e, 2);
            graf.pridejHranuDoGrafu((IKlic)a, (IKlic)b, h1);
            graf.pridejHranuDoGrafu((IKlic)a, (IKlic)c, h2);
            graf.pridejHranuDoGrafu((IKlic)c, (IKlic)d, h3);
            graf.pridejHranuDoGrafu((IKlic)d, (IKlic)e, h4);
            graf.pridejHranuDoGrafu((IKlic)a, (IKlic)e, h5);
            graf.pridejHranuDoGrafu((IKlic)b, (IKlic)e, h6);
            preklesliMapu();*/


            

            //graf.odeberHranuZGrafu(new Mesto(120, 50), new Mesto(60, 150), vratHranu(a, b));
            //DijkTest(c);
            //if (dijkstrovaCesta.Count == 0) MessageBox.Show("nic");
            //DijkstraTest(c);


            //zadám bod letiště - z toho se vypočítá čtverec
            //vytvořím levýHorní a pravýDolní
            //Mesto levyHorni = new Mesto((b.X - (b.LZS / 2)), (b.Y - (b.LZS / 2)));
            //Mesto pravyDolni = new Mesto((b.X + (b.LZS / 2)), (b.Y + (b.LZS / 2)));
            //string vypis = "V okruhu "+b.LZS+"px od LZS "+ b.NazevMesta +" (x:"+b.X+" | "+b.Y+") jsou následující města: \r\n";
            //LinkedList<Mesto> interval = graf.intervaloveVyhledavani(levyHorni, pravyDolni, b);
            //foreach (Mesto m in interval)
            //{
            //    vypis += (m.ToString());
            //}

            //Vysledky = vypis;



            //DijkstraTest(new Mesto(233, 144, "E", false, 0));




            //if (graf.Count > 0)
            //{ 
            //    preklesliMapu();
            //}


            DialogResult result = MessageBox.Show("Chceš načíst uložená data ze souboru?\r\nTato operace může trvat několik hodin.", "Načti ze souboru", MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
            if (result.Equals(DialogResult.OK))
            {
                pridejUzly(nactiMestaZeSouboruDoListu(), 0);
                nactiSilniceZeSouboru();
            }
        }


        //hranu najdu podle počátku a konce 

        #region Pomocné metody pro vrácení hrany a ohodnocení hrany
        public int vratOhodnoceniHrany(Mesto start, Mesto konec)
        {
            return vratHranu(start, konec).vratOhodnoceni();
        }

        public Hrana<Mesto, int> vratHranu(Mesto start, Mesto konec)
        {
            foreach (var item in graf.vratSeznamHranVUzlu(start))
            {
                if (item.vratUzelA().getY() == konec.getY() && item.vratUzelA().getX() == konec.getX())
                {

                    //Console.WriteLine("Vracím hranu");
                    return item;
                }

            }

            foreach (var item in graf.vratSeznamHranVUzlu(konec))
            {
                if (item.vratUzelA().getY() == start.getY() && item.vratUzelA().getX() == start.getX())
                {

                    //Console.WriteLine("Vracím hranu");
                    return item;
                }

            }

            //Console.WriteLine("NIC");
            return null;
        }
        #endregion

        #region Hlavní metody pro přidávání a odebírání z grafu
        public bool MAINpridaniUzluDoGrafu(int x, int y, string nazev, bool pozemni, int radius)
        {
            if (graf.pridejUzelDoGrafu(new Mesto(x, y, nazev, pozemni, radius))) return true; else return false;
        }

        public bool MAINpridejHranu(int x1, int y1, int x2, int y2, int ohodnoceni)
        {
            Mesto a = new Mesto(x1, y1);
            Mesto b = new Mesto(x2, y2);

            var x = vratHranu(a, b);
            if (x == null)
            {
                if (PROBIHAIMPORT) //aktuálně zakázané - řešení přímo přes metodu vkládání - TODO
                {
                    if (graf.pridejHranuDoGrafuIMPORT((IKlic)a, (IKlic)b, new Hrana<Mesto, int>(a, b, ohodnoceni))) return true; else return false;
                }
                else
                {
                    if (graf.pridejHranuDoGrafu((IKlic)a, (IKlic)b, new Hrana<Mesto, int>(a, b, ohodnoceni))) return true; else return false;
                }
            }
            else
            {
                LogText = "Hrana již existuje";

            }
            return false;
        }

        public bool MAINpridejHranu(Mesto m1, Mesto m2, int ohodnoceni)
        {

            var x = vratHranu(m1, m2);
            if (x == null)
            { 
                if (graf.pridejHranuDoGrafu((IKlic)m1, (IKlic)m2, new Hrana<Mesto, int>(m1, m2, ohodnoceni))) return true; else return false;
            }
            return false;
        }

        public bool MAINodeberHranu(int x1, int y1, int x2, int y2)
        {
            Mesto a = new Mesto(x1, y1);
            Mesto b = new Mesto(x2, y2);
            if (graf.odeberHranuZGrafu(a, b, vratHranu(a, b))) return true; else return false;
        }
        #endregion


        #region Obslužné metody pro práci s grafem
        public void odeberHranu(Point bod)
        {
            //přidání do označených

            if (!oznaceneBody.Contains(bod))
            {
                oznaceneBody.Add(bod);
            }

            if (oznaceneBody.Count == 2)
            {
                //přidání body do grafu
                int x1 = oznaceneBody.ElementAt(0).X;
                int y1 = oznaceneBody.ElementAt(0).Y;
                int x2 = oznaceneBody.ElementAt(1).X;
                int y2 = oznaceneBody.ElementAt(1).Y;
                int ohodnoceni = (int)numericUpDown1.Value;

                //samotné přidání hrany
                if (MAINodeberHranu(x1, y1, x2, y2))
                {
                    preklesliMapu();
                    LogText = "Hrana byla odebrána";
                }

                oznaceneBody.Clear();
            }
            else if (oznaceneBody.Count > 2)
            {

            }
        }

        /// <summary>
        /// Metoda pro přidávání uzlů přes grafické rozhraní
        /// </summary>
        /// <param name="e"></param>
        public void pridejUzel(Point bod)
        {
            string nazev = textBox2.Text;
            bool pozemni = checkBox1.Checked;
            int radius = (int)numericUpDown2.Value;
            int x = bod.X;
            int y = bod.Y;

            //samotné přidání do grafu
            if (MAINpridaniUzluDoGrafu(x, y, nazev, pozemni, radius))
            {
                LogText = "přidán uzel " + nazev + " na souřadnice " + x + " a " + y;

                preklesliMapu();
                textBox2.Text = GenerateRandomString(4);
                //Graphics g = Graphics.FromImage(pictureBox1.Image);
                ////tečka pro leteckou
                //if (radius != 0)
                //{
                //    g.FillEllipse(Brushes.Red, (x - 4), (y - 4), 16, 16);
                //    g.DrawEllipse(new Pen(Color.Red), ((x - (radius / 2)) + 4), ((y - (radius / 2)) + 4), radius, radius);
                //}
                ////tečka pro pozemní
                //if (pozemni)
                //{
                //    g.FillEllipse(Brushes.Pink, (x - 2), (y - 2), 12, 12);
                //}
                ////tečka pro město
                //g.FillEllipse(Brushes.Black, x, y, 8, 8);
                ////vypsání řetězce
                //g.DrawString(nazev, new Font("Tahoma", 8), Brushes.Black, (x - 20), (y + 15));
                //g.Save();
                //pictureBox1.Image = bmp;

            }
            else
            {
                //MessageBox.Show("Nepovedlo se přidat uzel");
                LogText = "Hrana nebyla přidána";
            }

        }

        public static string GenerateRandomString(int length)
        {
            //It will generate string with combination of small,capital letters and numbers
            char[] charArr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".ToCharArray();
            string randomString = string.Empty;
            Random objRandom = new Random();
            for (int i = 0; i < length; i++)
            {
                //Don't Allow Repetation of Characters
                int x = objRandom.Next(1, charArr.Length);
                if (!randomString.Contains(charArr.GetValue(x).ToString()))
                    randomString += charArr.GetValue(x);
                else
                    i--;
            }
            return randomString;
        }

        /// <summary>
        /// slouží pro přichytávání kurzoru k uzlům
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void najdiNejblizsiUzel(int x, int y)
        {
            Graphics g = Graphics.FromImage(pictureBox1.Image);

            foreach (Mesto mesto in graf)
            {
                int rozdilX = Math.Abs(x - mesto.X);
                int rozdilY = Math.Abs(y - mesto.Y);
                int radius = mesto.LZS;
                bool pozemni = mesto.PZS;

                if (rozdilX < 10 && rozdilY < 10)
                {
                    g.FillEllipse(Brushes.SteelBlue, (mesto.X - 4), (mesto.Y - 4), 16, 16);
                }
                else
                {

                    g.FillEllipse(Brushes.White, (mesto.X - 4), (mesto.Y - 4), 16, 16);
                    if (radius != 0)
                    {
                        g.FillEllipse(Brushes.Red, (mesto.X - 4), (mesto.Y - 4), 16, 16);
                        //g.DrawEllipse(new Pen(Color.Red), ((mesto.X - (radius / 2)) + 4), ((mesto.Y - (radius / 2)) + 4), radius, radius);
                    }
                    //tečka pro pozemní
                    if (pozemni)
                    {
                        g.FillEllipse(Brushes.Pink, (mesto.X - 2), (mesto.Y - 2), 12, 12);
                    }
                    //tečka pro město
                    g.FillEllipse(Brushes.Black, mesto.X, mesto.Y, 8, 8);
                }

                g.DrawString(mesto.NazevMesta, new Font("Tahoma", 8), Brushes.Black, (mesto.X - 20), (mesto.Y + 15));
            }

            g.Save();
            pictureBox1.Image = bmp;
        }

        public void pridejHranu(Point bod)
        {
            //přidání do označených

            if (!oznaceneBody.Contains(bod))
            {
                oznaceneBody.Add(bod);
            }

            if (oznaceneBody.Count == 2)
            {
                //přidání body do grafu
                int x1 = oznaceneBody.ElementAt(0).X;
                int y1 = oznaceneBody.ElementAt(0).Y;
                int x2 = oznaceneBody.ElementAt(1).X;
                int y2 = oznaceneBody.ElementAt(1).Y;
                int ohodnoceni = (int)numericUpDown1.Value;

                //samotné přidání hrany
                if (MAINpridejHranu(x1, y1, x2, y2, ohodnoceni))
                {
                    //vykreslení hrany v grafu
                    preklesliMapu();

                    LogText = "přidána hrana hrana s ohodnocením: " + ohodnoceni.ToString() + "(" + x1 + " | " + y1 + " : " + x2 + " | " + y2 + ")";
                }

                oznaceneBody.Clear();
            }
            else if (oznaceneBody.Count > 2)
            {

            }
        }

        public void pridejHranu(Mesto mesto)
        {
            //přidání do označených

            if (!zasobnikNaMesta.Contains(mesto))
            {
                zasobnikNaMesta.Add(mesto);
            }

            if (zasobnikNaMesta.Count == 2)
            {
                //přidání body do grafu
                Mesto m1 = zasobnikNaMesta.ElementAt(0);
                Mesto m2 = zasobnikNaMesta.ElementAt(1);
                int ohodnoceni = (int)numericUpDown1.Value;

                //samotné přidání hrany
                if (MAINpridejHranu(m1, m2, ohodnoceni))
                {
                    //vykreslení hrany v grafu
                    preklesliMapu();
                    LogText = "přidána hrana hrana s ohodnocením: " + ohodnoceni.ToString() + "(" + m1.getX() + " | " + m1.getY() + " : " + m2.getX() + " | " + m2.getY() + ")";
                }

                zasobnikNaMesta.Clear();
            }
            else if (zasobnikNaMesta.Count > 2)
            {

            }
        }

        

        public bool pridejHranu(Mesto m1, Mesto m2, int ohodnoceni)
        {

            Hrana<Mesto, int> h6 = new Hrana<Mesto, int>(m1, m2, ohodnoceni);
            if (MAINpridejHranu(m1, m2, ohodnoceni))
            {
                preklesliMapu();
                return true;
            }

            return false;

            
        }

        public bool pridejHranu(int x1, int y1, int x2, int y2, int ohodnoceni)
        {
            //samotné přidání hrany
            if (MAINpridejHranu(x1, y1, x2, y2, ohodnoceni))
            {
                preklesliMapu();

                return true;
            }

            return false;
        }

        public void vykresliHranu(int x1, int y1, int x2, int y2, int ohodnoceni)
        {
            //samotné přidání hrany
            if (MAINpridejHranu(x1, y1, x2, y2, ohodnoceni))
            {
                preklesliMapu();
            }
        }
        #endregion


        #region Metody pro překreslování plátna -> silnice, města atd...
        public void prekresliCelePlatno()
        {
            Graphics g = Graphics.FromImage(pictureBox1.Image);
            g.Clear(Color.White);
            g.Save();
            pictureBox1.Image = bmp;
        }

        public void prekresliMesta()
        {
            Graphics g = Graphics.FromImage(pictureBox1.Image);
            foreach (Mesto mesto in graf)
            {
                int radius = mesto.LZS;
                bool pozemni = mesto.PZS;
                {

                    g.FillEllipse(Brushes.White, (mesto.X - 4), (mesto.Y - 4), 16, 16);
                    if (radius != 0)
                    {
                        g.FillEllipse(new SolidBrush(Color.FromArgb(50, 95, 211, 112)), ((mesto.X - (radius / 2)) + 4), ((mesto.Y - (radius / 2)) + 4), radius, radius);
                        g.FillEllipse(Brushes.Red, (mesto.X - 4), (mesto.Y - 4), 16, 16);
                        g.DrawEllipse(new Pen(Color.Red), ((mesto.X - (radius / 2)) + 4), ((mesto.Y - (radius / 2)) + 4), radius, radius);



                    }
                    //tečka pro pozemní
                    if (pozemni)
                    {
                        g.FillEllipse(Brushes.Pink, (mesto.X - 2), (mesto.Y - 2), 12, 12);
                    }
                    //tečka pro město
                    g.FillEllipse(Brushes.Black, mesto.X, mesto.Y, 8, 8);
                }

                g.DrawString(mesto.NazevMesta, new Font("Tahoma", 8), Brushes.Black, (mesto.X - 20), (mesto.Y + 15));


                comboBox1.Items.Add(mesto);
            }
            g.Save();
            pictureBox1.Image = bmp;
        }

        public void prekresliSilnice()
        {

            int counterMesta = 0;
            int counterHrany = 0;
            int duplicity = 0;
            Graphics g = Graphics.FromImage(pictureBox1.Image);


            foreach (var item in graf)
            {
                foreach (var item2 in graf.vratSeznamHranVUzlu((IKlic)item))
                {
                    if ((item2.vratUzelB().getX() == item.getX() && item2.vratUzelB().getY() == item.getY()))
                    {
                        duplicity++;
                    }
                    else
                    {

                        int x1 = item2.vratUzelA().getX();
                        int y1 = item2.vratUzelA().getY();
                        int x2 = item2.vratUzelB().getX();
                        int y2 = item2.vratUzelB().getY();
                        int ohodnoceni = item2.vratOhodnoceni();

                        g.DrawLine(new Pen(Color.Black), x1, y1, x2, y2);
                        g.FillRectangle(new SolidBrush(Color.LightGray), new Rectangle((int)((x1 + x2) / 2), (int)((y1 + y2) / 2), 15, 13));
                        g.DrawString(ohodnoceni.ToString(), new Font("Tahoma", 8), Brushes.Black, ((x1 + x2) / 2), ((y1 + y2) / 2));
                        counterHrany++;
                    }

                }
                counterMesta++;
            }


            g.Save();
            pictureBox1.Image = bmp;

            toolStripStatusLabel5.Text = counterMesta.ToString();
            toolStripStatusLabel8.Text = counterHrany.ToString();
            //MessageBox.Show(duplicity.ToString());

        }

        public void preklesliMapu()
        {
            //vyprázdníme před každým vykreslením combobox na zadávání nehod
            comboBox1.Items.Clear();

            if (graf.Count() > 0)
            {
                prekresliCelePlatno();
                //pokud existuje cesta, tak ji vykreslím
                vykresliDijstra(dijkstrovaCesta);
                prekresliSilnice();
                prekresliMesta();
            }
            else { MessageBox.Show("Nejsou data k zobrazení");  }


        }
        #endregion


        //věci týkající se grafického rozhraní 


        /// <summary>
        /// provádění akcí při stisku myší --- controller
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        /// 

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (AkceTyp == 1)
            {

                pridejUzel(new Point(e.X, e.Y));
            }
            else if (AkceTyp == 2) // přidávání hran
            {
                foreach (Mesto mesto in graf)
                {
                    int rozdilX = Math.Abs(e.X - mesto.X);
                    int rozdilY = Math.Abs(e.Y - mesto.Y);
                    int radius = mesto.LZS;
                    bool pozemni = mesto.PZS;

                    if (rozdilX < 10 && rozdilY < 10)
                    {
                        //pridejHranu(new Point((mesto.X), (mesto.Y)));
                        //sem přidat metodu, která bude pracovat s městy
                        pridejHranu(mesto);


                        LogText = "Přidávám si do fronty uzel (x: " + mesto.X + "| y: " + mesto.Y + ")";
                    }
                }
            }
            else if (AkceTyp == 3)
            {
                foreach (Mesto mesto in graf)
                {
                    int rozdilX = Math.Abs(e.X - mesto.X);
                    int rozdilY = Math.Abs(e.Y - mesto.Y);
                    int radius = mesto.LZS;
                    bool pozemni = mesto.PZS;

                    if (rozdilX < 10 && rozdilY < 10)
                    {
                        odeberHranu(new Point((mesto.X), (mesto.Y)));
                        LogText = "Přidávám si do fronty uzel (x: " + mesto.X + "| y: " + mesto.Y + ")";
                    }
                }
            }
            else
            {
                MessageBox.Show("Vyberte akci");
            }

        }

        //dělá hezký efekt pro vybírání bodu
        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            toolStripStatusLabel1.Text = "X: " + e.X;
            toolStripStatusLabel2.Text = "Y: " + e.Y;

            if (AkceTyp == 2)
            {
                najdiNejblizsiUzel(e.X, e.Y);
            }
            else if (AkceTyp == 3)
            {
                najdiNejblizsiUzel(e.X, e.Y);
            }
        }

        #region Metody pro logování +  eventy
        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {

        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            AkceTyp = 1;
            LogText = "Zapnuta akce: přídávání uzlů";

        }

        private void button2_Click(object sender, EventArgs e)
        {
            AkceTyp = 2;
            LogText = "Zapnuta akce: přídávání hran";
        }

        private void button3_Click(object sender, EventArgs e)
        {
            AkceTyp = 3;
            LogText = "Zapnuta akce: Odebírání hran";
        }
        #endregion


        private void button4_Click(object sender, EventArgs e)
        {
            AkceTyp = 4;
            LogText = "Zapnuta akce: Zadávání nehody";
            najdiCestu();
            preklesliMapu();
            najdiCestu(true);

        }

        public void vykresliBodNehody(Mesto mesto1)
        {
            
                Graphics g = Graphics.FromImage(pictureBox1.Image);

                int xS = (int)(mesto1.X);
                int yS = (int)(mesto1.Y);

                g.FillEllipse(Brushes.Red, (xS - 10), (yS - 10), 20, 20);
                g.Save();
                pictureBox1.Image = bmp;
            

        }

        public void vykresliBodNehody(Mesto mesto1, Mesto mesto2 )
        {
            if (mesto2 != null)
            {
                double rozdilX = (((double)(mesto2.X - mesto1.X) / 100) * (double)(100 - trackBar1.Value));
                double rozdilY = (((double)(mesto2.Y - mesto1.Y) / 100) * (double)(100 - trackBar1.Value));


                Graphics g = Graphics.FromImage(pictureBox1.Image);

                int xS = (int)(mesto1.X + rozdilX);
                int yS = (int)(mesto1.Y + rozdilY);

                g.DrawLine(new Pen(Color.HotPink, 10), da.vychoziUzelCesty.X, da.vychoziUzelCesty.Y, xS, yS);
                g.DrawLine(new Pen(Color.Black), da.vychoziUzelCesty.X, da.vychoziUzelCesty.Y, xS, yS);
                g.FillEllipse(Brushes.Red, (xS - 10), (yS - 10), 20, 20);
                g.Save();
                pictureBox1.Image = bmp;
            }
          

        }
        //odkud se má hledat dijkstra
        public void najdiCestu(bool vykreslovaci = false)
        {
            string vybranaHodnota = comboBox1.Text.ToString();
            string vybranaHodnota2 = comboBox2.Text.ToString();
            if (vybranaHodnota != "" && vybranaHodnota2 != "")
            {
                string[] s = vybranaHodnota.Split('|');
                Mesto mesto1 = new Mesto(Int32.Parse(s[0]), Int32.Parse(s[1]), s[4], bool.Parse(s[2]), int.Parse(s[3]));
                s = vybranaHodnota2.Split('|');
                Mesto mesto2 = new Mesto(Int32.Parse(s[0]), Int32.Parse(s[1]), s[4], bool.Parse(s[2]), int.Parse(s[3]));

                int x = vratOhodnoceniHrany(mesto1, mesto2);
                label11.Text = (x.ToString()); //ohodnocení hrany


                double prvni = (double)(((100 - trackBar1.Value)));
                double druhy = (double)(((trackBar1.Value)));

                prvni = (int)Math.Round((prvni / 100) * x);
                druhy = (int)Math.Round((druhy / 100) * x);

                int p1 = (int)prvni;
                int p2 = (int)druhy;

                if (vykreslovaci)
                {
                    vykresliBodNehody(mesto1, mesto2);
                }
                else
                {
                    //DijkstraTest(mesto1, mesto2, p1, p2);
                    
                    dijkstrovaCesta = da.DijkstraN(graf, mesto1, mesto2, p1, p2);
                    Vysledky = da.Vysledky; 
                }
               

               

                label13.Text = prvni + " : " + druhy; //poměr
            }
            else if (vybranaHodnota != "")
            {
                string[] s = vybranaHodnota.Split('|');
                Mesto mesto1 = new Mesto(Int32.Parse(s[0]), Int32.Parse(s[1]), s[4], bool.Parse(s[2]), int.Parse(s[3]));



                if (vykreslovaci)
                {
                    vykresliBodNehody(mesto1);
                }
                else
                {
                    //DijkstraTest(mesto1);
                    
                    dijkstrovaCesta = da.DijkstraN(graf, mesto1);
                    Vysledky = da.Vysledky; 
                }
            }
            else MessageBox.Show("Nebyl vybrán start");

        }

        public void vypisPokryteUzly()
        {
            foreach (Mesto m in graf)
            {
                if (m.LZS > 0)
                {
                    najdiPokrytaMesta(m);
                }
            }

        }




        public int AkceTyp
        {
            get { return akceTyp; }
            set { akceTyp = value; }
        }

        #region Načítání a ukládání dat
        private void button5_Click(object sender, EventArgs e)
        {
            ulozDataDoTXT();
            //button5.Enabled = false;
        }

        /// <summary>
        /// Metoda pro uložení všech měst a cest
        /// </summary>
        private void ulozDataDoTXT()
        {
            //nejprve uložení měst a potom silnic

            string lines = vypisVsechnaMesta();
            System.IO.StreamWriter file = new System.IO.StreamWriter("DSAmesta.txt");
            file.WriteLine(lines);
            file.Close();

            string lines2 = vypisVsechnySilnice();
            System.IO.StreamWriter file2 = new System.IO.StreamWriter("DSAsilnice.txt");
            file2.WriteLine(lines2);
            file2.Close();

            LogText = "Data byla uložena";
        }


        private void button6_Click(object sender, EventArgs e)
        {
            //nactiMestaZeSouboru();
            
            pridejUzly(nactiMestaZeSouboruDoListu(),0);
            nactiSilniceZeSouboru();
        }

        private void nactiMestaZeSouboru()
        {
            
           
            int counterOK = 0;
            int counterBAD = 0;
            const string f1 = "DSAmesta.txt";
            using (StreamReader r = new StreamReader(f1))
            {

                string line;
                while ((line = r.ReadLine()) != null)
                {
                    string[] parts = line.Split(new[] { '|' });

                    //
                    if (parts.Length > 2)
                    {
                        Mesto x = new Mesto(Int32.Parse(parts[0]), Int32.Parse(parts[1]), parts[4].ToString(), bool.Parse(parts[2]), Int32.Parse(parts[3]));


                        if (graf.pridejUzelDoGrafu(x)) { Console.WriteLine("Načten uzel"); counterOK++; } else { counterBAD++; }
                    }

                }
            }

            LogText = "Proveden import měst. Naimportováno " + counterOK + " ze " + (counterOK + counterBAD);
            najdiNejblizsiUzel(0, 0);
        }

        private List<Mesto> nactiMestaZeSouboruDoListu()
        {

            graf.zrusGraf();
            int counterOK = 0;
            //int counterBAD = 0;
            const string f1 = "DSAmesta.txt";
            List<Mesto> listMesto = new List<Mesto>();
            using (StreamReader r = new StreamReader(f1))
            {

                string line;
                while ((line = r.ReadLine()) != null)
                {
                    string[] parts = line.Split(new[] { '|' });

                    //
                    if (parts.Length > 2)
                    {
                        Mesto x = new Mesto(Int32.Parse(parts[0]), Int32.Parse(parts[1]), parts[4].ToString(), bool.Parse(parts[2]), Int32.Parse(parts[3]));

                        listMesto.Add(x);
                        counterOK++;
                        //if (graf.pridejUzelDoGrafu(x)) { Console.WriteLine("Načten uzel"); counterOK++; } else { counterBAD++; }
                    }

                }
            }

            LogText = "Proveden import měst do listu. Naimportováno " + listMesto.Count + " ze " + counterOK;
            return listMesto;
        }

        /// <summary>
        /// Metoda pro mediánové vkládání
        /// </summary>
        /// <param name="seznamMest">List měst</param>
        /// <param name="uroven">Podle tohoto příznaku jdu podle x nebo y</param>
        private void pridejUzly(List<Mesto> seznamMest, int uroven)
        {
            if (seznamMest.Count != 0)
            {
                List<Mesto> setrideny = null;
                // podle X
                if ((uroven % 2) == 0)
                {
                    setrideny = seznamMest.OrderBy(o => o.X).ToList();
                }
                // podle Y
                else
                {
                    setrideny = seznamMest.OrderBy(o => o.Y).ToList();
                }
                List<Mesto> list1,list2 = new List<Mesto>();
                int median = (setrideny.Count() / 2);
                Mesto med = setrideny.ElementAt(median);
                graf.pridejUzelDoGrafu(med);
                //vždy rozdělím na dvě části
                list1 = setrideny.GetRange(0, median);
                list2 = setrideny.GetRange(median + 1, (setrideny.Count - (median + 1)));
                int xy = ((uroven + 1));
                pridejUzly(list1, xy);
                pridejUzly(list2, xy);
            }
        }

        static void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            
            e.Result = 123;    // Tato hodnota se předá do RunWorkerCompleted
        }

        private void nactiSilniceZeSouboru()
        {
            PROBIHAIMPORT = false;
            int counterOK = 0;
            int counterBAD = 0;
            const string f1 = "DSAsilnice.txt";
            using (StreamReader r = new StreamReader(f1))
            {

                string line;
                while ((line = r.ReadLine()) != null)
                {
                    string[] parts = line.Split(new[] { '|' });

                    //
                    if (parts.Length == 5)
                    {



                        //if (pridejHranu(Int32.Parse(parts[0]), Int32.Parse(parts[1]), Int32.Parse(parts[2]), Int32.Parse(parts[3]), Int32.Parse(parts[4])))
                        //{ Console.WriteLine("Načten uzel"); counterOK++; }
                        //else { counterBAD++; }

                        Mesto m1 = graf.najdiUzelPodleXY(Int32.Parse(parts[0]), Int32.Parse(parts[1]));
                        Mesto m2 = graf.najdiUzelPodleXY(Int32.Parse(parts[2]), Int32.Parse(parts[3]));

                        if (m1 != null && m2 != null)
                        {
                            if (pridejHranu(m1, m2, Int32.Parse(parts[4])))
                            { Console.WriteLine("Načten uzel"); counterOK++; }
                            else { counterBAD++; }
                        }
                        else
                        {
                            counterBAD++;
                        }
                    }

                }
            }

            LogText = "Proveden import silnic. Naimportováno " + counterOK + " ze " + (counterOK + counterBAD);
            najdiNejblizsiUzel(0, 0);
            PROBIHAIMPORT = false;
        }


        //metody pro výpis uzlů
        private void button7_Click(object sender, EventArgs e)
        {
            MessageBox.Show(vypisVsechnaMesta());
        }

        private string vypisVsechnaMesta()
        {
            string s = "";
            foreach (Mesto mesto in graf)
            {
                s += mesto.ToString() + "\r\n";
            }
            return s;
        }


        //metody pro výpis hran
        private void button8_Click(object sender, EventArgs e)
        {
            MessageBox.Show(vypisVsechnySilnice());
        }

        private string vypisVsechnySilnice()
        {
            string s = "";
            foreach (var item in graf.vratVsechnyHranyZeVsechUzlu())
            {
                s += item.ToString();
            }
            return s;

        }
        #endregion

        private void button9_Click(object sender, EventArgs e)
        {
            
                preklesliMapu();
          
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            comboBox2.Items.Clear();
            comboBox2.Text = "";
            string vybranaHodnota = comboBox1.Text.ToString();
            if (vybranaHodnota != "")
            {
                string[] s = vybranaHodnota.Split('|');
                comboBox2.Items.Clear();
                Mesto mesto = new Mesto(Int32.Parse(s[0]), Int32.Parse(s[1]), s[4], bool.Parse(s[2]), int.Parse(s[3]));


                foreach (Hrana<Mesto, int> hrana in graf.vratSeznamHranVUzlu(mesto))
                {


                    //výběr opačného uzlu
                    Mesto prvni, druhy;
                    if (hrana.vratUzelA().getX() == mesto.getX())
                    {
                        prvni = (Mesto)hrana.vratUzelB();
                        druhy = (Mesto)hrana.vratUzelA();
                    }
                    else
                    {
                        prvni = (Mesto)hrana.vratUzelA();
                        druhy = (Mesto)hrana.vratUzelB();
                    }

                    comboBox2.Items.Add(prvni);
                }
            }

        }

        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            label7.Text = (100 - trackBar1.Value).ToString();
            label6.Text = (trackBar1.Value.ToString());


            comboBox2_SelectedIndexChanged(sender, e);


            string vybranaHodnota = comboBox1.Text.ToString();
            string vybranaHodnota2 = comboBox2.Text.ToString();
            if (vybranaHodnota != "" && vybranaHodnota2 != "")
            {
                string[] s = vybranaHodnota.Split('|');
                Mesto mesto1 = new Mesto(Int32.Parse(s[0]), Int32.Parse(s[1]), s[4], bool.Parse(s[2]), int.Parse(s[3]));
                s = vybranaHodnota2.Split('|');
                Mesto mesto2 = new Mesto(Int32.Parse(s[0]), Int32.Parse(s[1]), s[4], bool.Parse(s[2]), int.Parse(s[3]));

                int x = vratOhodnoceniHrany(mesto1, mesto2);
                label11.Text = (x.ToString()); //ohodnocení hrany


                double prvni = (double)(((100 - trackBar1.Value)));
                double druhy = (double)(((trackBar1.Value)));

                prvni = (int)Math.Round((prvni / 100) * x);
                druhy = (int)Math.Round((druhy / 100) * x);

                int p1 = (int)prvni;
                int p2 = (int)druhy;

                //DijkstraTest(mesto1, mesto2, p1, p2);

                ////vzdálenost dvou bodů
                //double xx = Math.Pow((mesto1.getX() - mesto2.getX()), 2);
                //double yy = Math.Pow((mesto1.getY() - mesto2.getY()), 2);
                //double tmp = Math.Sqrt((xx + yy));




                label13.Text = prvni + " : " + druhy; //poměr
            }

        }

        private void comboBox2_SelectedIndexChanged(object sender, EventArgs e)
        {
            string vybranaHodnota = comboBox1.Text.ToString();
            string vybranaHodnota2 = comboBox2.Text.ToString();
            if (vybranaHodnota != "" && vybranaHodnota2 != "")
            {
                string[] s = vybranaHodnota.Split('|');
                Mesto mesto1 = new Mesto(Int32.Parse(s[0]), Int32.Parse(s[1]), s[4], bool.Parse(s[2]), int.Parse(s[3]));
                s = vybranaHodnota2.Split('|');
                Mesto mesto2 = new Mesto(Int32.Parse(s[0]), Int32.Parse(s[1]), s[4], bool.Parse(s[2]), int.Parse(s[3]));

                int x = vratOhodnoceniHrany(mesto1, mesto2);
                label11.Text = (x.ToString()); //ohodnocení hrany


                double prvni = (double)(((100 - trackBar1.Value)));
                double druhy = (double)(((trackBar1.Value)));

                prvni = (int)Math.Round((prvni / 100) * x);
                druhy = (int)Math.Round((druhy / 100) * x);

                label13.Text = prvni + " : " + druhy; //poměr
            }
        }

        private void button10_Click(object sender, EventArgs e)
        {
            vypisPokryteUzly();
        }

        private void button11_Click(object sender, EventArgs e)
        {
            graf.zrusGraf();
            prekresliCelePlatno();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {

        }





    }
}
